/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package kuti.grp5.ui;

import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.List;
import kuti.EWorldElementType;
import kuti.IChargingStation;
import kuti.IKuti;
import kuti.IObstacle;
import kuti.ISimulParams;
import kuti.IWorldElement;

/**
 * The purpose of this class is to tell its user if certain World Elements are
 * in a valid location.
 * @author Jocelyn
 */
public abstract class CollisionChecker {

    /**
     * A kuti placement is considered valid if it isn't
     * on top of each other with an obstacle or with another Kuti.
     * @param p - Point2D : center point of the Kuti
     * @param elts - List of WorldElement to check collisions with
     * @param kDiameter - Kuti's diameter
     * @return true if valid, false otherwise
     */
    public static boolean isKutiPlacementValid(Point2D p, List<IWorldElement> elts, double kDiameter) {
        
        // Checks if it's off limits
        if(p.getX() - kDiameter /2 < 0 || p.getY() - kDiameter/2 < 0)
            return false;
        
        if(p.getX() + kDiameter / 2 > ISimulParams.WORLD_WIDTH
                || p.getY() + kDiameter / 2 > ISimulParams.WORLD_HEIGHT)
            return false;
        
        for (IWorldElement w : elts) {
            if (w.getElementType() == EWorldElementType.KUTI) {
                IKuti k = (IKuti) w;
                Point2D center2 = k.getCenterPosition();
                if (p.distance(center2) < kDiameter) {
                    return false;
                }
            } else if (w.getElementType() == EWorldElementType.OBSTACLE
                    || w.getElementType() == EWorldElementType.MAGNETIC_OBSTACLE) {
                if (areKutiAndObstacleColliding(p, ((IObstacle) w).segment(), kDiameter)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * An obstacle placement is considered valid if it isn't on top of each other
     * with a Kuti.
     * @param obs - Line2D representing the obstacle
     * @param elts - List of WorldElement to check collisions with
     * @param kDiameter - Kuti's diameter
     * @return true if valid, false otherwise
     */
    public static boolean isObstaclePlacementValid(Line2D obs, List<IWorldElement> elts, double kDiameter) {
        if(obs.getP1().getX() < 0 || obs.getP1().getX() >= ISimulParams.WORLD_WIDTH) return false;
        if(obs.getP1().getY() < 0 || obs.getP1().getY() >= ISimulParams.WORLD_HEIGHT) return false;
        if(obs.getP2().getX() < 0 || obs.getP2().getX() >= ISimulParams.WORLD_WIDTH) return false;
        if(obs.getP2().getY() < 0 || obs.getP2().getY() >= ISimulParams.WORLD_HEIGHT) return false;
        
        for (IWorldElement w : elts) {
            if (w.getElementType() == EWorldElementType.KUTI) {
                IKuti k = (IKuti) w;
                if (areKutiAndObstacleColliding(k.getCenterPosition(), obs, kDiameter)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Tells if a Kuti and an obstacle are colliding.
     * @param kCenter -  Center point of the Kuti
     * @param obs - Line2D representing the obstacle
     * @param kDiameter - Kuti's diameter
     * @return true if the Kuti and the obstacle are colliding
     */
    public static boolean areKutiAndObstacleColliding(Point2D kCenter, Line2D obs, double kDiameter) {
        if (obs.ptSegDist(kCenter) <= kDiameter / 2) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * A station placement is considered valid if there is no other stations around
     * in a radius of kDiameter + radius of the charging station and if it's in the world's limits
     * @param sCenter - Center point of the charging station
     * @param radius - semi-diagonal of the charging station's rectangle
     * @param elts - List of WorldElement to check validity with
     * @param kDiameter - Kuti's diameter
     * @return true if position is valid, false otherwise
     */
    public static boolean isStationPlacementValid(Point2D sCenter, double radius, double width, double height, List<IWorldElement> elts, double kDiameter) {
        // Checks if the station is off limits
        if(sCenter.getX() - width / 2 < 0
                || sCenter.getY() - height / 2 < 0)
            return false;
        
        if (sCenter.getY() + height / 2 >= ISimulParams.WORLD_HEIGHT
                || sCenter.getX() + width / 2 >= ISimulParams.WORLD_WIDTH) 
            return false;
        

        for (IWorldElement w : elts) {
            if (w.getElementType() == EWorldElementType.CHARGING_STATION) {
                IChargingStation ics = (IChargingStation) w;
                Point2D center2 = ics.center();
                double radius2 = Math.sqrt(ics.height() * ics.height() + ics.width() * ics.width()) / 2;
                if (sCenter.distance(center2) < kDiameter + radius + radius2) {
                    return false;
                }
            }
        }
        return true;
    }
}
